/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: ConnectionManager.java,v $
 *
 */

package com.cidero.upnp;

import java.util.logging.Logger;

import org.cybergarage.upnp.*;
import org.cybergarage.upnp.device.InvalidDescriptionException;

import com.cidero.upnp.AbstractService;

/**
 *  ConnectionManager service abstract base class. Provides default
 *  implementations for some actions where possible, but mostly just
 *  defines dumb methods that just return 'false' (action not supported).
 *
 *  Notes:
 *
 *  Method header documentation in this class is intended to be the 
 *  'master' copy.  Derived classes should just include
 *  implemention-specific details in their method headers
 */
public class ConnectionManager extends AbstractService
{
  private static Logger logger = Logger.getLogger("com.cidero.upnp");

  /**
   *  AV ConnectionManager service official UPnP status codes
   *  (Service-specific codes in the range of 700-799). See Cybergarage
   *  UPnPStatus class for generic UPnP codes
   */
  public static final int INCOMPATIBLE_PROTOCOL_INFO = 701;
  public static final int INCOMPATIBLE_DIRECTIONS = 702;
  public static final int INSUFFICIENT_NETWORK_RESOURCES = 703;
  public static final int LOCAL_RESTRICTIONS = 704;
  public static final int ACCESS_DENIED = 705;
  public static final int INVALID_CONNECTION_REFERENCE = 706;
  public static final int NOT_IN_NETWORK = 707;


  /**
   * Constructor
   */
  public ConnectionManager( Device device )
    throws InvalidDescriptionException
  {
    super( device );  
    
    logger.fine("Entered ConnectionManager base class constructor");

    logger.fine("Leaving ConnectionManager constructor");
  }
  
  public ConnectionManager()
  {
  }

  public String getServiceType()
  {
    return "urn:schemas-upnp-org:service:ConnectionManager:1";
  }

  /**
   *  Initialize all required state variables to reasonable values 
   *  Optional device-specific state variables are initialized in the 
   *  derived class instances
   */
  public void initializeStateVariables()
  {
    //logger.fine("Entered - initializing state variables for base class");

    setStateVariable("SourceProtocolInfo", "" );
    setStateVariable("SinkProtocolInfo", "" );
    setStateVariable("CurrentConnectionIDs", "" );
  }

  /**
   * Get current connection info
   *
   * @param  action  UPnP action object
   *
   *    Action input arguments:
   *      ConnectionID              Id for connection. Will normally be 0
   *
   *    Action output arguments:
   *      RcsID                     Id of RenderingControl service associated
   *                                with connection 
   *      AVTransportId             Id of AVTransport service associated
   *                                with connection
   *      ProtocolInfo              Protocol info for connection. Example
   *                                would be 'http-get:*:audio/mpeg:*'
   *      PeerConnectionManager     Id of connection manager on peer side
   *                                of connection. This takes the form of
   *                                a "UDN/Service-Id" pair. 
   *      PeerConnectionId          Id of connection on peer side of 
   *                                connection
   *      Direction                 Direction of connection. Valid values are
   *                                'Input' or 'Output'
   *      Status                    Connection status. Valid values are:
   *                                  'OK'
   *                                  'ContentFormatMismatch'
   *                                  'InsufficientBandwidth'
   *                                  'UnreliableChannel'
   *                                  'Unknown'
   *
   * Notes:
   *  Connection manager service template says that:
   *
   *   RcsID should be 0 or -1
   *   AVTransportID should be 0 or -1
   *   PeerConnectionManager should be NULL (empty string)
   *   PeerConnectionID should be -1
   *   
   *  In general, it seems like the original notion for devices supporting
   *  multiple service instances within a single device has been shelved 
   *  in favor of using embedded UPnP devices. So all ID's passed around end
   *  up being set to 0
   *  
   *
   * NMPR Compliance Notes:
   *   Required Action: Yes
   *
   * TODO: Flush out this header's documentation
   */
  public boolean actionGetCurrentConnectionInfo( Action action )
  {
    /*
     *  Get & process input arguments. Unused ones just commented out for now
     */
    String connectId = action.getArgumentValue("ConnectionID");

    logger.fine("GetCurrentConnectionInfo: Entered, id = " +
                       connectId );
    /*
     * Set output arguments to valid defaults
     */
    action.setArgumentValue("RcsID", "0" );
    action.setArgumentValue("AVTransportId", "0" );
    action.setArgumentValue("ProtocolInfo", "" );
    action.setArgumentValue("PeerConnectionManager", "" );
    action.setArgumentValue("PeerConnectionId", "-1" );
    action.setArgumentValue("Direction", "Input" );
    action.setArgumentValue("Status", "Unknown" );

    return true;
  }

  /**
   * Get current connection ID's
   *
   * @param  action  UPnP action object
   *
   *    Action input arguments:
   *      None
   *
   *    Action output arguments:
   *      ConnectionIDs          A list of connection ID's. Since multiple
   *                             simultaneous connections aren't really
   *                             supported, this will normally return '0',
   *                             or NULL (empty string) if there are no
   *                             active connections
   *
   * NMPR Compliance Notes:
   *   Required Action: Yes
   *
   */
  public boolean actionGetCurrentConnectionIDs( Action action )
  {
    logger.fine("GetCurrentConnectionIDs: Entered");

    // Related variable is 'CurrentConnectionIDs'...
    action.setArgumentValueFromRelatedStateVariable("ConnectionIDs");

    return true;
  }

  /**
   * Get protocol information (lists of supported source/sink protocols 
   * for the device)
   *
   * @param  action  UPnP action object
   *
   *    Action input arguments:
   *      None
   *
   *    Action output arguments:
   *      Source     Comma-separated list (CSV) of all source protocols 
   *                 supported by this device.  If the device does not
   *                 function as a data source, the empty list ("") is
   *                 returned.
   *      Sink       Comma-separated list (CSV) of all sink protocols 
   *                 supported by this device.  Example:
   *
   *                  "http-get:*:audio/mpeg:*,http-get:*:audio/mpegurl:*"
   *
   *                 If the device does not function as a data sink, the
   *                 empty list ("") is returned.
   *                     
   * NMPR Compliance Notes:
   *   Required Action: Yes
   *
   */
  public boolean actionGetProtocolInfo( Action action )
  {
    logger.fine("GetProtocolInfo: Entered " );
    
    // Related variable is 'SourceProtocolInfo'...
    action.setArgumentValueFromRelatedStateVariable("Source");

    // Related variable is 'SinkProtocolInfo'...
    action.setArgumentValueFromRelatedStateVariable("Sink");

    return true;
  }

  /**
   * Prepare for connection. This action is used to request a connection
   * for the given protocol and direction
   *
   * @param  action  UPnP action object
   *
   *    Action input arguments:
   *      RemoteProtocolInfo        Protocol info ('http-get:*:audio/mpeg:*')
   *      PeerConnectionManager    
   *      PeerConnectionID
   *      Direction                 'Input' or 'Output' 
   *
   *    Action output arguments:
   *      ConnectionID              Id for connection
   *                                
   *      AVTransportId             Id of AVTransport service associated
   *                                with connection
   *      RcsId                     Id of RenderingControl service associated
   *                                with connection
   *
   * Notes:
   *
   *  Though the NMPR guidelines specify that this action should not be
   *  implemented, some current devices (Philips Streamium) support it,
   *  and don't work without it (As of 10/4/2004, the Philips devices 
   *  require a control point to issue a PrepareForConnection to get 
   *  the service ID's needed to issue actions, and the service ID's 
   *  are truly dynamic - not always 0)
   *
   * NMPR Compliance Notes:
   *   Required Action: Don't implement
   *
   */
  public boolean actionPrepareForConnection( Action action )
  {
    return false;   // Not implemented
  }

  /**
   * Close a connection that was instantiated using PrepareForConnection
   *
   * @param  action  UPnP action object
   *
   *    Action input arguments:
   *      ConnectionID              Id for connection
   *
   *    Action output arguments:
   *      None
   *
   * Notes:
   *
   *  Same notes as for PrepareForConnection - Philips uses this action,
   *  though the NMPR guidelines specify that this action should not be
   *  implemented
   *
   * NMPR Compliance Notes:
   *   Required Action: Don't implement
   */

  public boolean actionConnectionComplete( Action action )
  {
    return false;   // Not implemented
  }

  public String errorToString(int code)
  {
    return codeToString( code );
  }

  public static final String codeToString(int code)
  {
    switch (code) 
    {
      case INCOMPATIBLE_PROTOCOL_INFO: return "Incompatible protocol info";
      case INCOMPATIBLE_DIRECTIONS: return "Incompatible directions";
      case INSUFFICIENT_NETWORK_RESOURCES: return "Insufficient network resources";
      case LOCAL_RESTRICTIONS: return "Local restrictions";
      case ACCESS_DENIED: return "Access denied";
      case INVALID_CONNECTION_REFERENCE: return "Invalid connection reference";
      case NOT_IN_NETWORK: return "Not in network";
    }

    return UPnPStatus.code2String(code);
  }
  
  
}
